/*
 * Copyright (C) 2000-2008 Jens Nixdorf and various contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.mopore.jat.core.fadingmessage;
import static org.mopore.jat.gui.SingleRoundCornerRectangleFactory.produceSingleRoundCornerRectangel;

import java.awt.AlphaComposite;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Font;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.KeyboardFocusManager;
import java.awt.Paint;
import java.awt.RenderingHints;
import java.awt.Shape;
import java.awt.Toolkit;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;

import javax.swing.ImageIcon;
import javax.swing.JFrame;

import org.mopore.jat.core.fadingmessage.calibration.CalibrationInfo;
import org.mopore.jat.core.messaging.Message;
import org.mopore.jat.gui.FadingMode;
import org.mopore.jat.gui.Theme;
import org.mopore.jat.gui.SingleRoundCornerRectangleFactory.CornerType;

import com.sun.awt.AWTUtilities;

public class FadingMessageWindow extends JFrame implements Runnable {
	
	/**
	 * 
	 */
	private static final int WINDOW_HEIGHT = 80;
	/**
	 * 
	 */
	private static final int WINDOW_WIDTH = 250;
	/**
	 * 
	 */
	private static final int VERTICAL_START_OF_TEXT = 36;
	private static final Color NORMAL_TEXT_COLOR = new Color( 230, 230, 230);
	private Image offScreenImage = null;
	private Thread thread = null;
	protected RenderingHints rh = null;
	private boolean escape = false;
	private Shape innerShape;
	private Shape outerShape;
	private FadingMessageWindowAssistance assistance;
	private boolean done;
	private ButtonContainer buttonContainer;
	
	private BasicStroke stroke = new BasicStroke(
			3f, BasicStroke.CAP_ROUND,BasicStroke.JOIN_ROUND);
	
	private final Content content;
	private Composite imageComposite;
	private CalibrationInfo calibtrationInfo;
	private final Theme theme;
	
	
	public FadingMessageWindow( 
			Message message, 
			CalibrationInfo calibtrationInfo, 
			Theme theme
	) {
		this( message, calibtrationInfo, theme, null );
	}
	
	
	public FadingMessageWindow( 
			Message message, 
			CalibrationInfo calibtrationInfo, 
			Theme theme,
			ActionListener actionListener
	) {
		setUndecorated( true );
		String title = message.getTitle();
		ImageIcon icon = theme.getIcon();
		setIconImage( icon.getImage() );
		setTitle( title );
		this.done = false;
		this.content = new Content( message );
		this.theme = theme;
		this.setSize(WINDOW_WIDTH, WINDOW_HEIGHT);
		this.setBackground(Color.WHITE);
		imageComposite = 
			AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.55f );
		
		assistance = new FadingMessageWindowAssistance( actionListener, this );
		this.buttonContainer = new ButtonContainer( assistance );
		addMouseListener( 
				new MouseAdapter(){
					
					@Override
					public void mousePressed(MouseEvent e) {
						assistance.mouseDown();
					}
					
					@Override
					public void mouseReleased(MouseEvent e) {
						assistance.mouseUp();
					}
					
					@Override
					public void mouseEntered(MouseEvent e) {
						assistance.mouseIn();
					}
					
					public void mouseExited(MouseEvent e) {
						assistance.mouseOut();
					}
				}
		);
		
		addMouseMotionListener( 
				new MouseAdapter() {
					@Override
					public void mouseMoved(MouseEvent e) {
						assistance.mouseMoved( e );
					}
				}
			);
		
	
		this.rh  = new RenderingHints(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);
		
		rh.put(RenderingHints.KEY_RENDERING, 
				RenderingHints.VALUE_RENDER_QUALITY); 

		this.calibtrationInfo = calibtrationInfo;
		applyPosition();

		CornerType cornerType = calibtrationInfo.getCornerType();
		CornerType invertedCornerType = inverteCornerType( cornerType );
		adjustShapes( invertedCornerType );
		
		
		AWTUtilities.setWindowShape(this, innerShape );
		AWTUtilities.setWindowOpacity( this,  0f );
		
		this.setVisible(true);
		this.thread = new Thread(this);
		thread.start();
	}

	
	private void adjustShapes( CornerType cornerType ) {
		
		this.innerShape = produceSingleRoundCornerRectangel( 0, 0, getWidth(), 
				getHeight(), 20, 20, cornerType );
		
		this.outerShape = produceSingleRoundCornerRectangel( 0, 0, getWidth()-1, 
				getHeight()-1, 20+3  , 20+3, cornerType );
	}
	
	
	private void exit(){
		done = true;
		dispose();
	}
	
	
	public final void paint(Graphics g) {
		if (this.offScreenImage==null) {
			this.offScreenImage =  this.createImage(this.getWidth(),this.getHeight());
		}
		
		Graphics2D osG = (Graphics2D)this.offScreenImage.getGraphics();
		osG.setRenderingHints(rh);

		render(osG);
		osG.dispose();
		Graphics2D g2d = (Graphics2D) g;
		g2d.drawImage(this.offScreenImage,0,0,this);
	}

	
	protected void render(Graphics2D g){
		g.fill( innerShape );
		
		Color topColor = theme.getColorTop();
		Color bottomColor = theme.getColorBottom();
		
		Paint paint = g.getPaint();
		g.setPaint( 
				new GradientPaint( 
						0, 0, topColor,
						0, getHeight(), bottomColor
				)
		);
		g.fill( innerShape );
		g.setPaint( paint );
		
		g.setStroke( stroke );
		g.setColor( Color.BLACK );
		
		paint = g.getPaint();
		g.setPaint( 
				new GradientPaint( 
						0, 0, bottomColor,
						0, getHeight(), topColor
				)
		);
		g.draw( outerShape );
		
		g.setPaint( paint );
		
		Composite composite = g.getComposite();
		g.setComposite( imageComposite );
		BufferedImage image = content.getImage();
		if ( image != null ) {
			g.drawImage( image, 8, 26, null );
		}
		g.setComposite( composite );
		
		Color textColor;
		if ( assistance.isMouseIsIn() ) {
			textColor = Color.WHITE;
		}
		else {
			textColor = NORMAL_TEXT_COLOR;
		}
		
		g.setColor( textColor );
		
		content.assertOptimization( g );
		Font titleFont = content.getTitleFont();
		g.setFont( titleFont) ;
		String title = content.getTitle();
		g.drawString( title, 10, 20 );
		
		Font textFont = content.getTextFont();
		g.setFont( textFont) ;
		TextLine[] textLines = content.getLines();
		
		int y = VERTICAL_START_OF_TEXT;
		for ( TextLine textLine : textLines ) {
			String text = textLine.getText();
			int x = textLine.getX();
			g.drawString( text, x, y );
			y += 12;
		}
		
		buttonContainer.render( g );
	}
	
	
	public void shutdown(){
		this.escape = true;	 
	}
	
	
	/* (non-Javadoc)
	 * @see java.lang.Runnable#run()
	 */
	public void run(){
		
		KeyboardFocusManager manager = 
			KeyboardFocusManager.getCurrentKeyboardFocusManager();
		manager.clearGlobalFocusOwner();
		requestFocus();
		
		while (!escape){
			
			FadingMode mode = assistance.calculate();
			
			if ( mode == FadingMode.DONE ){
				done = true;
				shutdown();
			}

			float transparency = assistance.getTransparency();
			AWTUtilities.setWindowOpacity( this,  transparency );
			
			repaint();
			try {
				Thread.sleep(50);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}	
		}
		exit();
	}

	
	public final void update(java.awt.Graphics g) {
		this.paint(g);
	}
	
	
	public boolean isDone() {
		return done;
	}

	
	private CornerType inverteCornerType( CornerType cornerType ) {
		
			switch ( cornerType ) {
				case UPPER_LEFT:
					return CornerType.LOWER_RIGHT;
				case UPPER_RIGHT: 
					return CornerType.LOWER_LEFT;
				case LOWER_LEFT: 
					return CornerType.UPPER_RIGHT;
				default:  // LOWER_RIGHT
					return CornerType.UPPER_LEFT;
			}
	}
	
	private void applyPosition() {
		
		int horizontalOffset = calibtrationInfo.getHorizontalOffset();
		int verticalOffset = calibtrationInfo.getVerticalOffset();
		
		Toolkit toolkit = Toolkit.getDefaultToolkit();
        int screenWidth = (int) toolkit.getScreenSize().getWidth();
        int screenHeight = (int) toolkit.getScreenSize().getHeight();
		
		int x;
		int y;
		
		switch ( calibtrationInfo.getCornerType() ) {
			case UPPER_LEFT:{
				x = horizontalOffset;
				y = verticalOffset;
				break;
			}
			case UPPER_RIGHT:{
				x = screenWidth - WINDOW_WIDTH - horizontalOffset;
				y = verticalOffset;
				break;
			}
			case LOWER_RIGHT:{
				x = screenWidth - WINDOW_WIDTH - horizontalOffset;
				y = screenHeight - WINDOW_HEIGHT - verticalOffset;
				break;
			}
			default: { // lower left
				x = horizontalOffset;
				y = screenHeight - WINDOW_HEIGHT - verticalOffset;
				break;
			}			
		}
		setLocation( x, y );
	}
	
	

}
